/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Copyright (C) 2024-2025 Jim Gao <gaozhsoft@aliyun.com>
 *
 */
#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>

#include <linux/workqueue.h>
#include <linux/slab.h>

struct __drv_workqueue {
    struct workqueue_struct *workqueuestruct;
    struct work_struct workstruct;
    uint32_t num;
};
struct __drv_workqueue *drv_workqueue = NULL;

static void drv_workqueue_callback(struct work_struct *data)
{
    struct __drv_workqueue *drv_workqueue = container_of(data, struct __drv_workqueue, workstruct);

    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    printk("[%s +%d %s] drv_workqueue->num=0x%x\n", __FILE__, __LINE__, __func__, drv_workqueue->num);
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);
}

static int __init workqueue_drv_init(void)
{
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    drv_workqueue = kmalloc(sizeof(struct __drv_workqueue), GFP_KERNEL);
    if (NULL == drv_workqueue)
    {
        printk("[%s +%d %s] kmalloc(sizeof(struct __drv_workqueue)) failed\n", __FILE__, __LINE__, __func__);
  
    }
    drv_workqueue->num = 0x9090;
    printk("[%s +%d %s] drv_workqueue->num=0x%x\n", __FILE__, __LINE__, __func__, drv_workqueue->num);

    drv_workqueue->workqueuestruct = create_singlethread_workqueue("drv_singlethread_workqueue_name");

    INIT_WORK(&(drv_workqueue->workstruct), drv_workqueue_callback);
    (void) queue_work(drv_workqueue->workqueuestruct, &(drv_workqueue->workstruct));
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);
    return 0;
}

static void __exit workqueue_drv_exit(void)
{
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    if (NULL != drv_workqueue->workqueuestruct)
    {
        flush_workqueue(drv_workqueue->workqueuestruct);
        destroy_workqueue(drv_workqueue->workqueuestruct);
    }
    if (NULL != drv_workqueue)
    {
        kfree(drv_workqueue);
        drv_workqueue = NULL;
    }
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);

}

module_init(workqueue_drv_init);
module_exit(workqueue_drv_exit);

MODULE_AUTHOR("Jim Gao <gaozhsoft@aliyun.com>");
MODULE_DESCRIPTION("basic example for dedicated workqueue driver");
MODULE_LICENSE("GPL v2");

